https://stackoverflow.com/questions/64597525/r-magick-square-crop-and-circular-mask
https://www.r-bloggers.com/2016/11/extracting-exif-data-from-photos-using-r/
This tutorial was developed with the support of Althouse & Meade inc., and many of the ideas in the tutorial are based on ideas found here were synthesized by Kyle Nessen and collaborators.
Here we aim to evaluate the potential use of spherical photos for the estimation of canopy cover. The goal is to eventually apply this towards analyzing the habitat of monarchs in local eucalyptus groves. Traditionally this is done with a class of tools called densiometers. These tools can be biased, and other tools have been developed to overcome these biases like the GRS Densiometer. Similarly, methods using LiDAR and Photogrammetry (Andersen, McGaughey, and Reutebuch (2005) ), however LiDAR and other remote sensing platforms are not always available or affordable.
It is for that reason that this tutorial will aim at finding a more universal solution. Spherical cameras are small, portable, and relatively inexpensive, many offering built in GPS units at much smaller costs than bulkier hemispherical cameras. Much of the framework for this process was developed by Andis Arietta who also released several open license tools for conversions online (Arietta (2020) ).
library(leaflet) #for interactive webmaps
library(sf)
library(magick) #image manipulation
library(imager)
library(plotrix)
library(hemispheR)
Data was captured by me (Sam Ericksen) using a GoPro 360 camera on a 6’ pole while walking through the Coastal Access Monarch Butterfly Preserve in Los Osos, California. The area, can be seen here:
capture occurred over the course of a few hours, and involved grid lining out the northern grove on foot. The path of capture can be seen below.
tracks <- read_sf("PathShape/Euc_Forest_path.shp")
tracks <- st_zm(tracks) #drop z dimension
leaflet(tracks$geometry) %>%
addProviderTiles("Esri.WorldImagery") %>%
addPolylines()
For ease of looping through large numbers of pictures, the first in
the function chain will be built to take in a file path to an image, If
RAM is not of concern for the number of images you are working with you
may wish to read all images into memory using image_read()
, and create a function to take in the magick images. For the sake of
example, we will simply read in four 360 images.
img_paths <- paste0("360_Pics/", list.files("360_Pics"))
num_pics <- length(img_paths)
rand_ind <- sample.int(num_pics, 2) #save index for later to continue to work with the same pictures
test_img_paths <-img_paths[rand_ind] #grab 2 random 360 pictures from the picture directory
360 degree photos are in essence spherical photos, and they are captured as planar (rectangular) projections of a sphere. This means that to create a rectangular projection of a hemisphere, we must cut the spherical projection in half along its horizontal axis. Eventually all of these functions will be applied to thousands of photos, so everything will be created in functions, before it is applied to photos, so we don’t read thousands of photos into the ram all at once.
sphere_to_hemi_rect <- function(image_path){
#'input: path to spherical image
#'output: rectangular projection of hemisphere image
sphere_rect_img <- image_read(image_path)
hemi_rect <- image_crop(sphere_rect_img, "100%x50%") #crop off bottom half of image
return(hemi_rect)
}
rect_imgs <- sphere_to_hemi_rect(test_img_paths)
image_append( rect_imgs, stack = TRUE)